package sys

import (
	"os"
	"strings"
	"sync"

	sys2 "gitee.com/zfd81/dbrs/errs"
)

// SystemVariableScope represents the scope of a sys variable.
type SystemVariableScope byte

const (
	// SystemVariableScope_Global is set when the sys variable exists only in the global context.
	SystemVariableScope_Global SystemVariableScope = iota
	// SystemVariableScope_Session is set when the sys variable exists only in the session context.
	SystemVariableScope_Session
	// SystemVariableScope_Both is set when the sys variable exists in both the global and session contexts.
	SystemVariableScope_Both
)

// String returns the scope as an uppercase string.
func (s SystemVariableScope) String() string {
	switch s {
	case SystemVariableScope_Global:
		return "GLOBAL"
	case SystemVariableScope_Session:
		return "SESSION"
	case SystemVariableScope_Both:
		return "GLOBAL, SESSION"
	default:
		return "UNKNOWN_SYSTEM_SCOPE"
	}
}

// globalSystemVariables is the underlying type of SystemVariables.
type globalSystemVariables struct {
	mutex      *sync.RWMutex
	sysVarVals map[string]interface{}
}

// SystemVariables is the collection of sys variables for this process.
var SystemVariables = &globalSystemVariables{&sync.RWMutex{}, make(map[string]interface{})}

func (sv *globalSystemVariables) AssignValues(vals map[string]interface{}) error {
	sv.mutex.Lock()
	defer sv.mutex.Unlock()
	for varName, val := range vals {
		varName = strings.ToLower(varName)
		_, ok := systemVars[varName]
		if !ok {
			return sys2.ErrUnknownSystemVariable.New(varName)
		}
		sv.sysVarVals[varName] = val
	}
	return nil
}

// NewSessionMap returns a new map of sys variable values for sessions.
func (sv *globalSystemVariables) NewSessionMap() map[string]interface{} {
	sv.mutex.RLock()
	defer sv.mutex.RUnlock()
	sessionVals := make(map[string]interface{}, len(sv.sysVarVals))
	for key, val := range sv.sysVarVals {
		sessionVals[key] = val
	}
	return sessionVals
}

func (sv *globalSystemVariables) GetGlobal(name string) (interface{}, bool) {
	sv.mutex.RLock()
	defer sv.mutex.RUnlock()
	name = strings.ToLower(name)
	v, ok := sv.sysVarVals[name]
	if ok {
		return v, true
	}
	return nil, false
}

func (sv *globalSystemVariables) SetGlobal(name string, val interface{}) error {
	sv.mutex.Lock()
	defer sv.mutex.Unlock()
	name = strings.ToLower(name)
	_, ok := systemVars[name]
	if !ok {
		return sys2.ErrUnknownSystemVariable.New(name)
	}
	sv.sysVarVals[name] = val
	return nil
}

// init initializes SystemVariables as it functions as a global variable.
func init() {
	for k, v := range systemVars {
		SystemVariables.sysVarVals[k] = v
	}
}

var systemVars = map[string]interface{}{
	"activate_all_roles_on_login":               int8(0),
	"admin_address":                             "",
	"admin_port":                                int64(33062),
	"admin_ssl_ca":                              "",
	"admin_ssl_capath":                          "",
	"admin_ssl_cert":                            "",
	"admin_ssl_cipher":                          "",
	"admin_ssl_crl":                             "",
	"admin_ssl_crlpath":                         "",
	"admin_ssl_key":                             "",
	"admin_tls_ciphersuites":                    "",
	"admin_tls_version":                         "TLSv1,TLSv1.1,TLSv1.2,TLSv1.3",
	"authentication_windows_log_level":          int64(2),
	"authentication_windows_use_principal_name": int8(1),
	"autocommit":                                int8(1),
	"automatic_sp_privileges":                   int8(1),
	"auto_generate_certs":                       int8(1),
	"session": map[string]interface{}{
		"auto_increment_increment": int64(1),
	},
	"auto_increment_offset":  int64(1),
	"avoid_temporal_upgrade": int8(0),
	"back_log":               int64(-1),
	//TODO: add to dolt
	"basedir":                                      "",
	"big_tables":                                   int8(0),
	"bind_address":                                 "*",
	"binlog_gtid_simple_recovery":                  int8(1),
	"block_encryption_mode":                        "aes-128-ecb",
	"bulk_insert_buffer_size":                      uint64(8388608),
	"caching_sha2_password_digest_rounds":          int64(5000),
	"caching_sha2_password_auto_generate_rsa_keys": int8(1),
	"caching_sha2_password_private_key_path":       "private_key.pem",
	"caching_sha2_password_public_key_path":        "public_key.pem",
	"character_set_client":                         Collation_Default.CharacterSet().String(),
	"character_set_connection":                     Collation_Default.CharacterSet().String(),
	"character_set_database":                       Collation_Default.CharacterSet().String(),
	"character_set_filesystem":                     "binary",
	"character_set_results":                        Collation_Default.CharacterSet().String(),
	"character_set_server":                         Collation_Default.CharacterSet().String(),
	"character_set_system":                         Collation_Default.CharacterSet().String(),
	"character_sets_dir":                           "",
	"check_proxy_users":                            int8(0),
	"collation_connection":                         Collation_Default.String(),
	"collation_database":                           Collation_Default.String(),
	"collation_server":                             Collation_Default.String(),
	"completion_type":                              "NO_CHAIN",
	"concurrent_insert":                            "AUTO",
	"connect_timeout":                              int64(10),
	"core_file":                                    int8(0),
	"create_admin_listener_thread":                 int8(0),
	"cte_max_recursion_depth":                      int64(1000),
	"datadir":                                      "",
	"debug_sync":                                   "",
	"default_authentication_plugin":                "caching_sha2_password",
	"default_collation_for_utf8mb4":                "utf8mb4_0900_ai_ci",
	"default_password_lifetime":                    int64(0),
	"default_storage_engine":                       "InnoDB",
	"default_table_encryption":                     int8(0),
	"default_tmp_storage_engine":                   "InnoDB",
	"default_week_format":                          int64(0),
	"delay_key_write":                              "ON",
	"delayed_insert_limit":                         uint64(100),
	"delayed_insert_timeout":                       int64(300),
	"delayed_queue_size":                           uint64(1000),
	"disabled_storage_engines":                     "",
	"disconnect_on_expired_password":               int8(1),
	"div_precision_increment":                      int64(4),
	"dragnet.log_error_filter_rules":               "drop",
	"end_markers_in_json":                          int8(0),
	"enforce_gtid_consistency":                     "OFF",
	"eq_range_index_dive_limit":                    int64(200),
	"event_scheduler":                              "ON",
	"explicit_defaults_for_timestamp":              int8(1),
	"external_user":                                "",
	"flush":                                        int8(0),
	"flush_time":                                   int64(0),
	"foreign_key_checks":                           int8(1),
	"ft_boolean_syntax":                            `+ -><()~*:""&|`,
	"ft_max_word_len":                              int64(0),
	"ft_min_word_len":                              int64(4),
	"ft_query_expansion_limit":                     int64(20),
	"ft_stopword_file":                             "",
	"general_log":                                  int8(0),
	"general_log_file":                             "host_name.log",
	"generated_random_password_length":             int64(20),
	"group_concat_max_len":                         uint64(1024),
	"gtid_executed":                                "",
	"gtid_executed_compression_period":             int64(0),
	"gtid_mode":                                    "OFF",
	"gtid_next":                                    "AUTOMATIC",
	"gtid_owned":                                   "",
	"gtid_purged":                                  "",
	"have_statement_timeout":                       int8(0),
	"histogram_generation_max_mem_size":            uint64(20000000),
	"host_cache_size":                              int64(-1),
	"hostname":                                     "",
	"immediate_server_version":                     int64(80017),
	"init_connect":                                 "",
	"information_schema_stats_expiry":              int64(86400),
	"init_file":                                    "",
	"inmemory_joins":                               int8(0),
	"interactive_timeout":                          int64(28800),
	"internal_tmp_disk_storage_engine":             "INNODB",
	"internal_tmp_mem_storage_engine":              "TempTable",
	"join_buffer_size":                             uint64(262144),
	"keep_files_on_create":                         int8(0),
	"key_buffer_size":                              uint64(8388608),
	"key_cache_age_threshold":                      uint64(300),
	"key_cache_block_size":                         int64(1024),
	"key_cache_division_limit":                     int64(100),
	"large_files_support":                          int8(0),
	"large_pages":                                  int8(0),
	"large_page_size":                              int64(0),
	"last_insert_id":                               int64(0),
	"lc_messages":                                  "en_US",
	"lc_messages_dir":                              "",
	"lc_time_names":                                "",
	"license":                                      "GPL",
	"local_infile":                                 int8(0),
	"lock_wait_timeout":                            int64(31536000),
	"log_error":                                    "",
	"log_error_services":                           "log_filter_internal; log_sink_internal",
	"log_error_suppression_list":                   "",
	"log_error_verbosity":                          int64(2),
	"log_output":                                   "FILE",
	"log_queries_not_using_indexes":                int8(0),
	"log_raw":                                      int8(0),
	"log_slow_admin_statements":                    int8(0),
	"log_slow_extra":                               int8(0),
	"log_syslog":                                   int8(1),
	"log_syslog_facility":                          "daemon",
	"log_syslog_include_pid":                       int8(1),
	"log_syslog_tag":                               "",
	"log_timestamps":                               "UTC",
	"log_throttle_queries_not_using_indexes":       int64(0),
	"long_query_time":                              float64(10),
	"low_priority_updates":                         int8(0),
	"lower_case_file_system":                       int8(0),
	"lower_case_table_names":                       int64(0),
	"mandatory_roles":                              "",
	"max_allowed_packet":                           int64(1073741824),
	"max_connect_errors":                           uint64(100),
	"max_connections":                              int64(151),
	"max_delayed_threads":                          int64(20),
	"max_digest_length":                            int64(1024),
	"max_error_count":                              int64(1024),
	"max_execution_time":                           int64(0),
	"max_heap_table_size":                          uint64(16777216),
	"max_insert_delayed_threads":                   int64(0),
	"max_join_size":                                uint64(18446744073709551615),
	"max_length_for_sort_data":                     int64(4096),
	"max_points_in_geometry":                       int64(65536),
	"max_prepared_stmt_count":                      int64(16382),
	"max_seeks_for_key":                            uint64(18446744073709551615),
	"max_sort_length":                              int64(1024),
	"max_sp_recursion_depth":                       int64(0),
	"max_user_connections":                         int64(0),
	"max_write_lock_count":                         uint64(18446744073709551615),
	"mecab_rc_file":                                "",
	"metadata_locks_cache_size":                    int64(1024),
	"metadata_locks_hash_instances":                int64(8),
	"min_examined_row_limit":                       uint64(0),
	"myisam_data_pointer_size":                     int64(6),
	"myisam_max_sort_file_size":                    int64(9223372036853727232),
	"myisam_mmap_size":                             uint64(18446744073709551615),
	"myisam_recover_options":                       "OFF",
	"myisam_repair_threads":                        uint64(1),
	"myisam_sort_buffer_size":                      uint64(8388608),
	"myisam_stats_method":                          "nulls_unequal",
	"myisam_use_mmap":                              int8(0),
	"mysql_native_password_proxy_users":            int8(0),
	"named_pipe":                                   int8(0),
	"named_pipe_full_access_group":                 "",
	"ndbinfo_version":                              "",
	"net_buffer_length":                            int64(16384),
	"net_read_timeout":                             int64(30),
	"net_retry_count":                              uint64(10),
	"net_write_timeout":                            int64(60),
	"new":                                          int8(0),
	"ngram_token_size":                             int64(2),
	"offline_mode":                                 int8(0),
	"old":                                          int8(0),
	"old_alter_table":                              int8(0),
	"open_files_limit":                             uint64(5000),
	"optimizer_prune_level":                        int64(1),
	"optimizer_search_depth":                       int64(62),
	//TODO: add proper support for this
	//"optimizer_switch": {
	//	Name: "optimizer_switch",
	//	Scope: SystemVariableScope_Both,
	//	Dynamic: true,
	//	SetVarHintApplies: true,
	//	Type: NewSystemSetType("optimizer_switch"),
	//	Default: "",
	//},
	"optimizer_trace":                 "",
	"optimizer_trace_features":        "",
	"optimizer_trace_limit":           int64(1),
	"optimizer_trace_max_mem_size":    int64(1048576),
	"optimizer_trace_offset":          int64(-1),
	"original_server_version":         int64(80017),
	"parser_max_mem_size":             uint64(18446744073709551615),
	"partial_revokes":                 int8(0),
	"password_history":                int64(0),
	"password_require_current":        int8(0),
	"password_reuse_interval":         int64(0),
	"performance_schema":              int8(1),
	"persisted_globals_load":          int8(1),
	"persist_only_admin_x509_subject": "",
	"pid_file":                        "",
	"plugin_dir":                      "",
	"port":                            int64(3306),
	"preload_buffer_size":             int64(32768),
	"print_identified_with_as_hex":    int8(0),
	"protocol_compression_algorithms": "zlib,zstd,uncompressed",
	"protocol_version":                int64(0),
	"proxy_user":                      "",
	"pseudo_slave_mode":               int8(0),
	"pseudo_thread_id":                int64(0),
	//TODO: implement block sizes
	//"query_alloc_block_size": {
	//	Name: "query_alloc_block_size",
	//	Scope: SystemVariableScope_Both,
	//	Dynamic: true,
	//	SetVarHintApplies: false,
	//	Type: NewSystemIntType("query_alloc_block_size", 1024, 4294967295, false),
	//	Default: int64(8192),
	//},
	"query_cache_size": int8(1),
	"query_cache_type": "OFF",
	//"query_prealloc_size": {
	//	Name: "query_prealloc_size",
	//	Scope: SystemVariableScope_Both,
	//	Dynamic: true,
	//	SetVarHintApplies: false,
	//	Type: NewSystemUintType("query_prealloc_size", 8192, 18446744073709551615),
	//	Default: uint64(8192),
	//},
	"rand_seed1": int64(0),
	//TODO: implement block sizes
	//"range_alloc_block_size": {
	//	Name: "range_alloc_block_size",
	//	Scope: SystemVariableScope_Both,
	//	Dynamic: true,
	//	SetVarHintApplies: true,
	//	Type: NewSystemUintType("range_alloc_block_size", 4096, 18446744073709547520),
	//	Default: uint64(4096),
	//},
	"range_optimizer_max_mem_size":            uint64(8388608),
	"rbr_exec_mode":                           "STRICT",
	"read_buffer_size":                        int64(131072),
	"read_only":                               int8(0),
	"read_rnd_buffer_size":                    int64(262144),
	"regexp_stack_limit":                      int64(8000000),
	"regexp_time_limit":                       int64(32),
	"require_row_format":                      int8(0),
	"require_secure_transport":                int8(0),
	"resultset_metadata":                      "FULL",
	"secondary_engine_cost_threshold":         float64(100000.000000),
	"schema_definition_cache":                 int64(256),
	"secure_file_priv":                        "",
	"select_into_buffer_size":                 int64(131072),
	"select_into_disk_sync":                   int8(0),
	"select_into_disk_sync_delay":             int64(0),
	"session_track_gtids":                     "OFF",
	"session_track_schema":                    int8(1),
	"session_track_state_change":              int8(0),
	"session_track_system_variables":          "time_zone, autocommit, character_set_client, character_set_results, character_set_connection",
	"session_track_transaction_info":          "OFF",
	"sha256_password_auto_generate_rsa_keys":  int8(1),
	"sha256_password_private_key_path":        "private_key.pem",
	"sha256_password_proxy_users":             int8(0),
	"sha256_password_public_key_path":         "public_key.pem",
	"shared_memory":                           int8(0),
	"shared_memory_base_name":                 "MYSQL",
	"show_create_table_skip_secondary_engine": int8(0),
	"show_create_table_verbosity":             int8(0),
	"show_old_temporals":                      int8(0),
	"skip_external_locking":                   int8(1),
	"skip_name_resolve":                       int8(0),
	"skip_networking":                         int8(0),
	"skip_show_database":                      int8(0),
	"slow_launch_time":                        int64(2),
	"slow_query_log":                          int8(0),
	"slow_query_log_file":                     "host_name-slow.log",
	"socket":                                  "/tmp/mysql.sock",
	"sort_buffer_size":                        uint64(262144),
	"sql_auto_is_null":                        int8(0),
	"sql_big_selects":                         int8(1),
	"sql_buffer_result":                       int8(0),
	"sql_log_off":                             int8(0),
	"sql_mode":                                "STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION",
	"sql_notes":                               int8(1),
	"sql_quote_show_create":                   int8(1),
	"sql_require_primary_key":                 int8(0),
	"sql_safe_updates":                        int8(0),
	"sql_select_limit":                        int64(2147483647),
	"sql_warnings":                            int8(0),
	"ssl_ca":                                  "",
	"ssl_capath":                              "",
	"ssl_cert":                                "",
	"ssl_cipher":                              "",
	"ssl_crl":                                 "",
	"ssl_crlpath":                             "",
	"ssl_fips_mode":                           "OFF",
	"ssl_key":                                 "",
	"stored_program_cache":                    int64(256),
	"stored_program_definition_cache":         int64(256),
	"super_read_only":                         int8(0),
	"syseventlog.facility":                    "daemon",
	"syseventlog.include_pid":                 int8(1),
	"syseventlog.tag":                         "",
	"system_time_zone":                        "UTC",
	"table_definition_cache":                  int64(-1),
	"table_encryption_privilege_check":        int8(0),
	"table_open_cache":                        int64(4000),
	"table_open_cache_instances":              int64(16),
	"tablespace_definition_cache":             int64(256),
	"temptable_max_mmap":                      uint64(1073741824),
	"temptable_max_ram":                       uint64(1073741824),
	"temptable_use_mmap":                      int8(1),
	"thread_cache_size":                       int64(-1),
	"thread_handling":                         "one-thread-per-connection",
	"thread_pool_algorithm":                   int64(0),
	"thread_pool_high_priority_connection":    int64(0),
	"thread_pool_max_active_query_threads":    int64(0),
	"thread_pool_max_unused_threads":          int64(0),
	"thread_pool_prio_kickup_timer":           int64(1000),
	"thread_pool_size":                        int64(16),
	"thread_pool_stall_limit":                 int64(6),
	//TODO: implement block sizes
	//"thread_stack": {
	//	Name: "thread_stack",
	//	Scope: SystemVariableScope_Global,
	//	Dynamic: false,
	//	SetVarHintApplies: false,
	//	Type: NewSystemUintType("thread_stack", 131072, 18446744073709551615),
	//	Default: uint64(286720),
	//},
	"time_zone": "SYSTEM",
	//TODO: this needs to utilize a function as the value is not static
	"timestamp":        float64(1000.0),
	"tls_ciphersuites": "",
	"tls_version":      "TLSv1,TLSv1.1,TLSv1.2,TLSv1.3",
	"tmp_table_size":   uint64(16777216),
	"tmpdir":           GetTmpdirSessionVar(),
	//TODO: implement block sizes
	//"transaction_alloc_block_size": {
	//	Name: "transaction_alloc_block_size",
	//	Scope: SystemVariableScope_Both,
	//	Dynamic: true,
	//	SetVarHintApplies: false,
	//	Type: NewSystemIntType("transaction_alloc_block_size", 1024, 131072, false),
	//	Default: int64(8192),
	//},
	"transaction_isolation":        "REPEATABLE-READ",
	"transaction_prealloc_size":    int64(4096),
	"transaction_read_only":        int8(0),
	"tx_isolation":                 "REPEATABLE-READ",
	"tx_read_only":                 int8(0),
	"unique_checks":                int8(1),
	"updatable_views_with_limit":   int8(1),
	"use_secondary_engine":         "ON",
	"validate_user_plugins":        int8(1),
	"version":                      "",
	"version_comment":              "",
	"version_compile_machine":      "",
	"version_compile_os":           "",
	"version_compile_zlib":         "",
	"wait_timeout":                 int64(28800),
	"windowing_use_high_precision": int8(1),
}

func GetTmpdirSessionVar() string {
	ret := os.Getenv("TMPDIR")
	if ret != "" {
		return ret
	}

	ret = os.Getenv("TEMP")
	if ret != "" {
		return ret
	}

	ret = os.Getenv("TMP")
	if ret != "" {
		return ret
	}

	return ""
}
